﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Postnuclear.Collections;
using Postnuclear.Test.Helpers;

namespace Postnuclear.Test.Collections
  {
  /// <summary>
  /// Represents a test class for the <see cref="ObservableLinkedList{T}.Node"/> class.
  /// </summary>
  [TestClass]
  public sealed class ObservableLinkedListNodeTest
    : TestClassBase
    {
    #region Public

    // Methods

    /// <summary>
    /// Initializes this instance.
    /// </summary>
    [TestInitialize]
    public void Initialize()
      {
      Node = new ObservableLinkedList<int>.Node();
      }

    /// <summary>
    /// A test for <see cref="ObservableLinkedList{T}.Node.Index"/> property and <see cref="ObservableLinkedList{T}.Node.IndexChanged"/> event.
    /// </summary>
    [TestMethod]
    public void IndexTest()
      {
      int count = 0;
      int propertyChangedCount = 0;
      Node.IndexChanged += (_, __) => ++count;
      Node.PropertyChanged += (_, e) => propertyChangedCount += e.PropertyName == "Index" ? 1 : 0;
      ObservableLinkedList<int>.Node next = new ObservableLinkedList<int>.Node();
      ObservableLinkedList<int>.Node previous = new ObservableLinkedList<int>.Node();
      Assert.AreEqual(0, count);
      Assert.AreEqual(0, propertyChangedCount);
      Assert.AreEqual(-1, previous.Index);
      Assert.AreEqual(-1, Node.Index);
      Assert.AreEqual(-1, next.Index);

      Node.List = next.List = previous.List = new ObservableLinkedList<int>();
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(0, Node.Index);
      Assert.AreEqual(0, next.Index);

      Node.Previous = previous;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(1, Node.Index);
      Assert.AreEqual(0, next.Index);

      Node.Next = next;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(1, Node.Index);
      Assert.AreEqual(0, next.Index);

      next.Previous = Node;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(1, Node.Index);
      Assert.AreEqual(2, next.Index);

      Node.Previous = null;
      Assert.AreEqual(3, count);
      Assert.AreEqual(3, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(0, Node.Index);
      Assert.AreEqual(1, next.Index);

      Node.Next = null;
      Assert.AreEqual(3, count);
      Assert.AreEqual(3, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(0, Node.Index);
      Assert.AreEqual(1, next.Index);

      next.Previous = null;
      Assert.AreEqual(3, count);
      Assert.AreEqual(3, propertyChangedCount);
      Assert.AreEqual(0, previous.Index);
      Assert.AreEqual(0, Node.Index);
      Assert.AreEqual(0, next.Index);
      }

    /// <summary>
    /// A test for <see cref="ObservableLinkedList{T}.Node.List"/> property and <see cref="ObservableLinkedList{T}.Node.ListChanged"/> event.
    /// </summary>
    [TestMethod]
    public void ListTest()
      {
      int count = 0;
      int propertyChangedCount = 0;
      Node.ListChanged += (_, __) => ++count;
      Node.PropertyChanged += (_, e) => propertyChangedCount += e.PropertyName == "List" ? 1 : 0;
      Assert.AreEqual(0, count);
      Assert.AreEqual(0, propertyChangedCount);
      Assert.IsNull(Node.List);

      ObservableLinkedList<int> list = new ObservableLinkedList<int>();
      Node.List = list;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(list, Node.List);

      Node.List = list;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(list, Node.List);

      Node.List = null;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.IsNull(Node.List);
      }

    /// <summary>
    /// A test for <see cref="ObservableLinkedList{T}.Node.Next"/> property and <see cref="ObservableLinkedList{T}.Node.NextChanged"/> event.
    /// </summary>
    [TestMethod]
    public void NextTest()
      {
      int count = 0;
      int propertyChangedCount = 0;
      Node.NextChanged += (_, __) => ++count;
      Node.PropertyChanged += (_, e) => propertyChangedCount += e.PropertyName == "Next" ? 1 : 0;
      Assert.AreEqual(0, count);
      Assert.AreEqual(0, propertyChangedCount);
      Assert.IsNull(Node.Next);

      ObservableLinkedList<int>.Node next = new ObservableLinkedList<int>.Node();
      Node.Next = next;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(next, Node.Next);

      Node.Next = next;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(next, Node.Next);

      Node.Next = null;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.IsNull(Node.Next);
      }

    /// <summary>
    /// A test for <see cref="ObservableLinkedList{T}.Node.Previous"/> property and <see cref="ObservableLinkedList{T}.Node.PreviousChanged"/> event.
    /// </summary>
    [TestMethod]
    public void PreviousTest()
      {
      int count = 0;
      int propertyChangedCount = 0;
      Node.PreviousChanged += (_, __) => ++count;
      Node.PropertyChanged += (_, e) => propertyChangedCount += e.PropertyName == "Previous" ? 1 : 0;
      Assert.AreEqual(0, count);
      Assert.AreEqual(0, propertyChangedCount);
      Assert.IsNull(Node.Previous);

      ObservableLinkedList<int>.Node previous = new ObservableLinkedList<int>.Node();
      Node.Previous = previous;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(previous, Node.Previous);

      Node.Previous = previous;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(previous, Node.Previous);

      Node.Previous = null;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.IsNull(Node.Previous);
      }

    /// <summary>
    /// A test for <see cref="ObservableLinkedList{T}.Node.Value"/> property and <see cref="ObservableLinkedList{T}.Node.ValueChanged"/> event.
    /// </summary>
    [TestMethod]
    public void ValueTest()
      {
      int count = 0;
      int propertyChangedCount = 0;
      Node.ValueChanged += (_, __) => ++count;
      Node.PropertyChanged += (_, e) => propertyChangedCount += e.PropertyName == "Value" ? 1 : 0;
      Assert.AreEqual(0, count);
      Assert.AreEqual(0, propertyChangedCount);
      Assert.AreEqual(default(int), Node.Value);

      Node.Value = 3;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(3, Node.Value);

      Node.Value = 3;
      Assert.AreEqual(1, count);
      Assert.AreEqual(1, propertyChangedCount);
      Assert.AreEqual(3, Node.Value);

      Node.Value = 5;
      Assert.AreEqual(2, count);
      Assert.AreEqual(2, propertyChangedCount);
      Assert.AreEqual(5, Node.Value);
      }

    #endregion

    #region Private

    // Properties

    private ObservableLinkedList<int>.Node Node
      {
      get;
      set;
      }

    #endregion
    }
  }
